﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace JustMoveIt.Logic
{
    class JustMoveItLogic
    {
        private FolderHelper _fh;
        public readonly string ExtFileLocation;
        public readonly string IniFileLocation;
        
        
        private static JustMoveItLogic _instance;
        public string _appPath;
        public static JustMoveItLogic Instance
        {
            get
            {
                return _instance;
            }
        }

        /// <summary>
        /// The private constructor used to initialize the Logic class.
        /// </summary>
        /// <param name="appPath">The path of the executable.</param>
        private JustMoveItLogic(string appPath)
        {
            _appPath = appPath;
            ExtFileLocation = Path.Combine(appPath, "fileData.ini");
            IniFileLocation = Path.Combine(appPath,"config.ini");
            _fh = new FolderHelper();
            Settings.Instance.Source = "";
            Settings.Instance.Dest = "";
        }
        /// <summary>
        /// Init method to initalize the Logic class
        /// </summary>
        /// <param name="appPath">The path of the executable</param>
        public static void Init(string appPath)
        {
            _instance = new JustMoveItLogic(appPath);
            _instance.Init();
        }
        /// <summary>
        /// Force the object to initalize
        /// </summary>
        public void Init()
        {
            LoadConfigData(IniFileLocation);
            LoadExtData(ExtFileLocation);
        }
        /// <summary>
        /// Load the extension file
        /// </summary>
        /// <param name="fileName">The name of the file</param>
        public void LoadExtData(string fileName)
        {
            try
            {
                _fh.InitExtension(fileName);
            }
            catch (Exception e)
            {
                //something went wrong
                Logger.Instance.Write(e);
            }
        }
        /// <summary>
        /// Load the extension file with the default filename.
        /// </summary>
        public void LoadExtData()
        {
            LoadExtData(ExtFileLocation);
        }

        /// <summary>
        /// JustMoveIt 
        ///     The main logic of the program - duh
        /// </summary>
        /// <param name="src">The source of the files to move</param>
        /// <param name="dest">The destination to move the files to</param>
        public void JustMoveIt(DirectoryInfo src, DirectoryInfo dest)
        {
            Settings.Instance.Source = src.FullName;
            Settings.Instance.Dest = dest.FullName;
            Save();

            if (src.Exists)
            {
                if (!dest.Exists)
                {
                    try
                    {
                        dest.Create();
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show("Fail to create destination Directory : ");
                        Logger.Instance.Write(e);
                        return;
                        
                    }
                }
                FileInfo[] AlltheFiles = src.GetFiles();
                foreach (FileInfo info in AlltheFiles)
                {
                    string folderName = _fh.Convert(info.Extension, dest.FullName);
                    if (folderName != null)//need to move
                    {
                        DirectoryInfo finalDestination = new DirectoryInfo(folderName);
                        if (!finalDestination.Exists)
                        {
                            try
                            {
                                finalDestination.Create();
                            }
                            catch (Exception e) //something went wrong when creating folder.
                            {
                                Logger.Instance.Write(e);
                                continue;
                            }
                        }
                        string finalPath = GetSuitablePath(finalDestination, info);
                        info.MoveTo(finalPath);
                    }
                }
                DirectoryInfo[] AlltheDirectories = src.GetDirectories();
                foreach (DirectoryInfo info in AlltheDirectories)
                {
                    string folderName = "Folders";
                    DirectoryInfo finalDestination = new DirectoryInfo(Path.Combine(dest.FullName, folderName));
                    if (!finalDestination.Exists)
                    {
                        finalDestination.Create();
                    }
                    string finalPath = getSuitablePath(finalDestination, info);
                    DirectoryInfo finalPathDirectory = new DirectoryInfo(finalPath);
                    if (!finalPathDirectory.Exists)
                    {
                        
                        SimpleMove(info, finalPathDirectory);
                        if (info.GetFiles().Length + info.GetFiles().Length == 0)
                        {
                            info.Delete();
                        }
                    }
                    else
                    {
                        Logger.Instance.Write("ERROR SHOULD NOT HAPPEN !!!");
                    }
                    
                }

            }
        }
        /// <summary>
        /// Recursively move the folder. 
        ///     This method is added as the folders cannot be move to a different root directly.
        /// </summary>
        /// <param name="src">Source</param>
        /// <param name="dest">Destination</param>
        private void SimpleMove(DirectoryInfo src, DirectoryInfo dest)
        {
            if (dest.Exists)
            {
                Logger.Instance.Write("Destination should not exist");
                return;
            }
            try
            {
                dest.Create();
            }
            catch (Exception e)
            {
                Logger.Instance.Write("Fail to create folder : " + dest.FullName);
                Logger.Instance.Write(e);
                return;
            }

            FileInfo[] AlltheFiles = src.GetFiles();
            foreach (FileInfo info in AlltheFiles)
            {
                string finalPath = GetSuitablePath(dest, info);
                try
                {
                    info.MoveTo(finalPath);
                }
                catch (Exception e)
                {
                    Logger.Instance.Write("Move failed : " + finalPath);
                    Logger.Instance.Write(e);
                }
            }
            DirectoryInfo[] AlltheDirectories = src.GetDirectories();
            foreach (DirectoryInfo info in AlltheDirectories)
            {
                string finalPath = getSuitablePath(dest, info);
                DirectoryInfo finalPathDirectory = new DirectoryInfo(finalPath);
                SimpleMove(info, finalPathDirectory);
                if (info.GetFiles().Length + info.GetFiles().Length == 0)
                {
                    info.Delete();
                }
            }
        }

        public void JustMoveIt(DirectoryInfo src)
        {
            if (Settings.Instance.Dest != null && Settings.Instance.Dest != "")
            {
                JustMoveIt(src, new DirectoryInfo(Settings.Instance.Dest));
            }
            else
            {
                MessageBox.Show("Destination Not Set!");
            }
        }

        public void JustMoveIt(FileInfo info, DirectoryInfo dest)
        {
            try
            {
                string folderName = _fh.Convert(info.Extension, dest.FullName);
                if (folderName != null) //need to move
                {
                    DirectoryInfo finalDestination = new DirectoryInfo(folderName);
                    if (!finalDestination.Exists)
                    {
                        try
                        {
                            finalDestination.Create();
                        }
                        catch (Exception e) //something went wrong when creating folder.
                        {
                            Logger.Instance.Write(e);
                            return;
                        }
                    }
                    string finalPath = GetSuitablePath(finalDestination, info);
                    info.MoveTo(finalPath);
                }
            }
            catch (Exception e)
            {
                Logger.Instance.Write(e);
            }
        }
        public void JustMoveIt(FileInfo info)
        {
            if (Settings.Instance.Dest != null && Settings.Instance.Dest != "")
            {
                JustMoveIt(info, new DirectoryInfo(Settings.Instance.Dest));
            }
            else
            {
                MessageBox.Show("Destination Not Set!");
            }
        }


        private string getSuitablePath(DirectoryInfo finalDestination, DirectoryInfo info)
        {
            string finalPath = Path.Combine(finalDestination.FullName, info.Name);
            if (!Directory.Exists(finalPath))
            {
                return finalPath;
            }
            int i = 0;
            while (true)
            {
                string newFinal = finalPath + i;
                if (!File.Exists(newFinal))
                {
                    return newFinal;
                }
                i++;

            }
        }

        private void Save()
        {
            try
            {
                FileInfo info = new FileInfo(IniFileLocation);
                if (!info.Exists)
                {
                    info.Create();
                }

                TextWriter writer = new StreamWriter(IniFileLocation, false);
                writer.WriteLine(Settings.Instance.Source);
                writer.WriteLine(Settings.Instance.Dest);
                writer.WriteLine(Settings.Instance.Registry);
                writer.Flush();
                writer.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        //Find a suitable file name for it to move to.
        private string GetSuitablePath(DirectoryInfo finalDestination, FileInfo info)
        {
            string finalPath = Path.Combine(finalDestination.FullName, Path.GetFileName(info.FullName));
            if (!File.Exists(finalPath))
            {
                return finalPath;
            }
            int i = 0;
            while (true)
            {
                string newFinal = finalPath + i;
                if (!File.Exists(newFinal))
                {
                    return newFinal;
                }
                i++;

            }
        }

        

        private void LoadConfigData(string fileName)
        {
            try
            {
                FileInfo info = new FileInfo(fileName);
                if (!info.Exists)
                {
                    info.Create();
                    return;
                }
                TextReader reader = new StreamReader(fileName);
                string source = reader.ReadLine();
                string dest = reader.ReadLine();
                bool check = false;
                Boolean.TryParse(reader.ReadLine(), out check);
                Settings.Instance.Source = source;
                Settings.Instance.Dest = dest;
                Settings.Instance.Registry = check;
                try
                {
                    reader.Close();
                }
                catch (Exception)
                {
                }
            }
            catch (Exception e)
            {
                Logger.Instance.Write(e);
            }
        }
    }
}
